// -*- mode: c++ -*-
#ifndef __interpreter_h_
#define __interpreter_h_
#include <fstream>
#include <set>
#include <queue>
#include <string>
#include <map>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "pugixml.hpp"
#include "state.h"

#include "statefactory.h"
#include "transitionTarget.h"

// logging
#include "log4cxx/logger.h"
#include "log4cxx/basicconfigurator.h"
#include "log4cxx/helpers/exception.h"
using namespace log4cxx;
using namespace log4cxx::helpers;

const std::string nul = "";
typedef std::vector<std::string> strvec;
class Event
{
public:
    std::string value;
    Event(const string& v = nul):
	value(v)
	{
	};
};

class Interpreter
{
    class findstr 
    {
	// Checks if node's name is in the list of strings passed on the ctor.
    public:

	findstr(const std::string *src)
	    {
		m_str=src;
	    }

	bool operator() (pugi::xml_node node) 
	    {
		bool result = false;
		std::string name = node.name();
		int i=0;
      
		if (m_str == NULL)
		    return result;

		while (m_str[i] != "")
		{
		    if (m_str[i] == name)
		    {
			result = true;
			break;
		    }
		    ++i;
		}
		return result;
	    }

    private:
	const std::string *m_str;
    };

public:
    Interpreter(void);
    virtual ~Interpreter();
  
    bool parse();
    void buildmachine(std::string const &docfile);
    void run(void);

    pugi::xml_document doc;	// parsed document.
    std::string docname;

    strset configuration;  
    strset previousConfiguration;
    //std::set<State*> statesToInvoke;

    //strset configuration;
    std::queue<Event*> internalEventQueue, externalEventQueue;

  
    StateFactory factory;
    TransitionTarget *m_root;
    bool continueLoop;

    void execTransition(Transition*);
    void enterStates(TransitionList&);
    TtMap targets, *pt;  
    
    bool isCompound(const TransitionTarget *s);
    bool isParallel(const TransitionTarget *s)
	{
	    if (!s)
		return false;
	    return s->type == TransitionTarget::Parallel;
	};
    bool isAtomic(const TransitionTarget *s)
	{
	    if (!s)
		return false;
	    return s->type == TransitionTarget::Atomic;
	}
    bool isPreempted(TransitionTarget *s, TransitionList &transitions);
    void push_event(string &v)
	{
	    externalEventQueue.push(new Event(v));
	}

protected:
//    LoggerPtr logger;
    
private:
    TransitionTarget*  parseStateNode(pugi::xml_node  node, TransitionTarget *);
    void dig(pugi::xml_node p, TransitionTarget*);
    void tell(TransitionTarget*);

    TargetList properAncestors(const TransitionTarget *state, 
			       const TransitionTarget *upperBound);
    TransitionTarget *findLCA( const TargetList &states);

    void findStates(strvec &targets, TargetList &);


    findstr is_state;
    findstr is_transition;
    findstr is_initial;


    void addStatesToEnter(TransitionTarget *s, strset &statesToEnter,
			  strset &statesForDefaultEntry);

    void startEventLoop(void);
    TransitionList selectTransitions(Event *event=0);
    void mainEventLoop(void);
    Event* dequeueExternalEvent(void);

    Event* dequeueInternalEvent(void)
	{
	    if (!internalEventQueue.empty())
	    {
		Event* e = internalEventQueue.front();
		internalEventQueue.pop();
		return e;
	    }
	    return 0;
	};
    void microstep(Event *, TransitionList&);
    strset exitStates(Event *, TransitionList&);
    TransitionList selectEventlessTransitions(void);

    void startup(TransitionTarget &p);

    bool mainloopflag;

};
#endif
